package utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import beans.AlgorithmDetail;
import beans.HttpConfig;
import beans.HttpResult;
import beans.TokenValue;
import dao.AlgorithmDao;
import net.HttpRequest;
import net.sf.json.JSONObject;
import portal.beans.Job;

/**
 * @author zhuyaokunll@foxmail.com
 * @date 2018/8/16 15:48
 */
@Component
@SuppressWarnings("Duplicates")
public class FtpuploadUtil {
	@Autowired
	AlgorithmDao algorithmDao;
	/**
	 * 工具包的本地路径
	 */
	private String uploadToolUri;
	/**
	 * 脚本文件后缀 .bat或者.sh
	 */
	private String postfix;

	private SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");

	public FtpuploadUtil() {
		uploadToolUri = HttpConfig.uploadToolUri;
		String rootPath = Thread.currentThread().getContextClassLoader().getResource("/").getPath();
		postfix = "";
		if (HttpConfig.serverPlatform.equals("linux")) {
			uploadToolUri = rootPath + uploadToolUri;
			postfix = ".sh";
		} else {
			postfix = ".bat";
			rootPath = rootPath.substring(1, rootPath.length());
			uploadToolUri = rootPath + uploadToolUri;
		}
	}

	/**
	 * 使用一个算法的id来查询其文件uri，并将其文件上传至ftp，返回ftp文件的list
	 * ftp算法文件路径:HttpConfig.ftpAlgorithmUri+algorithmDetail.getId()+yyyy-MM-dd-HH-mm-ss"+algorithmFileName;
	 * eg:/home/algorithm/489/2018-22-22-22-22-22/cpu12.zip
	 * 
	 * @param algorithmId
	 *            算法id
	 * @return
	 */
	public List<String> uploadAlgorithmFileByAlgorithmId(String algorithmId) {
		Log4jInit.logger.info("上传了ID为：" + algorithmId + "的算法文件");
		
		AlgorithmDetail algorithmDetail = algorithmDao.getAlgorithmDetail(algorithmId, null);
		String algorithmFileName = algorithmDetail.getLocationUri();
		algorithmFileName = algorithmFileName.substring(algorithmFileName.lastIndexOf("/") + 1);
		String ftpAlgorithmFileName = HttpConfig.ftpAlgorithmUri + algorithmDetail.getId() + "/" + sf.format(new Date())
				+ "/" + algorithmFileName;
		/*
		 * return
		 * uploadAlgorithmFileByAlgorithmUri(true,algorithmDetail.getLocationUri
		 * (), ftpAlgorithmFileName,UUID.randomUUID().toString().substring(10));
		 */
		return uploadAlgorithmFileByAlgorithmUri(false, algorithmDetail.getLocationUri(), ftpAlgorithmFileName,
				UUID.randomUUID().toString().substring(10));
	}

	
	public void chmod(String filePath) throws IOException {
		if (HttpConfig.serverPlatform.equals("linux")) {
			Process p = Runtime.getRuntime().exec("chmod 777 " + filePath);

			/* 为"错误输出流"单独开一个线程读取之,否则会造成标准输出流的阻塞 */
			Thread t = new Thread(new StreamGobbler(p.getErrorStream(), "ErrorStream"));
			t.start();
			

			try {
				p.waitFor();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				p.destroy();
			}
		}
	}

	/**
	 * 上传一个文件并返回其在ftp的文件位置
	 * 
	 * @param filePath
	 *            本地文件位置
	 * @param ftpFileUri
	 *            ftp文件位置
	 * @return
	 * @throws IOException
	 *             生成脚本文件出错
	 */
	public String uploadFile(String filePath, String ftpFileUri) throws IOException {
		
		String scriptFileUri = generateScriptFile(ftpFileUri, filePath);
		if (createFolders(ftpFileUri) && runBat(scriptFileUri)) {
			StaticUtil.deleteFile(scriptFileUri);
		//	StaticUtil.deleteFile(filePath);
		//	StaticUtil.deleteFile(filePath.substring(0, filePath.lastIndexOf("/") + 1));
			return ftpFileUri;
		} else {
			return null;
		}
	}
	
	public String uploadFileByCopy(String filePath, String ftpFileUri){
		
		File f = new File(filePath);
		if (f.exists() && (!f.isDirectory())) {
			Process p;
			String cmd = "cp "+filePath+" "+ftpFileUri;
			String path = ftpFileUri.substring(0,ftpFileUri.lastIndexOf("/"));
			Log4jInit.logger.info("file path :"+path);
			Log4jInit.logger.info("copy file:"+cmd);
			try {
				p = Runtime.getRuntime().exec("mkdir -p "+path);
				p = Runtime.getRuntime().exec(cmd);
				p = Runtime.getRuntime().exec("chmod 777 -R "+path);
//				p.destroy();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			return ftpFileUri;
		} else {
			return null;
		}
		
	}
	

	/**
	 * 利用ftp工具将fileUri处的文件上传到ftp的ftpFileUri文件处，返回ftpFileUri，用list包住
	 * 如果fileUri为zip格式的文件，返回一个list
	 * 
	 * @param isAlgorithmFile
	 *            标识是否是算法文件或者是xml文件
	 * @param fileUri
	 *            本地文件 C:/a.exe
	 * @param ftpFileUri
	 *            ftp文件 /home/2.exe
	 * @param executeAlgorithmFileName
	 *            这是需要将算法文件中的中文修改为uuid的随机值，值为uuid截取一段
	 * @return
	 */
	public List<String> uploadAlgorithmFileByAlgorithmUri(boolean isAlgorithmFile, String fileUri, String ftpFileUri,
			String executeAlgorithmFileName) {
		List<String> result = new ArrayList<String>();
		try {
			List<String> fileMap = null;
			chmod(uploadToolUri);
			if (isAlgorithmFile && fileUri.substring(fileUri.lastIndexOf("."), fileUri.length()).equals(".zip")) {
				/**
				 * 如果上传算法文件且文件格式是zip,将zip解压到同名文件夹,并取出当中所有文件的路径
				 */
				StaticUtil.unzip(fileUri);
				String dirPath = fileUri.substring(0, fileUri.lastIndexOf("."));
				String foldName = dirPath.substring(dirPath.lastIndexOf("/") + 1, dirPath.length());
				String targetFilePath = dirPath + "/";
				if (executeAlgorithmFileName == null)
					return null;
				fileMap = StaticUtil.getAllFiles(dirPath, foldName, executeAlgorithmFileName);
				for (int i = 0; i < fileMap.size(); i++) {
					fileUri = fileMap.get(i);
					// 远端路径重拼装
					ftpFileUri = ftpFileUri.substring(0, ftpFileUri.lastIndexOf("/"))
							+ fileUri.substring(fileUri.lastIndexOf("/"));
					updateState(ftpFileUri, generateScriptFile(ftpFileUri, fileUri), postfix, result);
					if (fileUri.contains(executeAlgorithmFileName)) {
						StaticUtil.deleteFile(fileUri);
					}
				}
			} else {
				/**
				 * 如果是其他情况，则ftpFileUri是早已封装好的，不需再处理
				 */
				updateState(ftpFileUri, generateScriptFile(ftpFileUri, fileUri), postfix, result);
			}
			return result;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 利用ftp工具将job.fileUri处的文件上传到ftp的ftpFileUri文件处，返回ftpFileUri，用list包住
	 */
	public List<String> uploadJobFileByJobUri(Job job) {
		String tmp = job.getFileUri().substring(job.getFileUri().lastIndexOf("/"), job.getFileUri().length());
//		String ftpFileUri = HttpConfig.ftpJobUri + job.getJobHash() + "/" + sf.format(new Date()) + "/" + job.getName();
		String ftpFileUri = HttpConfig.ftpJobUri + job.getJobHash() + "/" + sf.format(new Date()) + tmp;
		List<String> result = new ArrayList<String>();
		try {
			List<String> fileMap = null;
			chmod(uploadToolUri);
			String fileUri = job.getFileUri();
			if (fileUri.substring(fileUri.lastIndexOf("."), fileUri.length()).equals(".zip")) {
				/**
				 * 如果上传算法文件且文件格式是zip,将zip解压到同名文件夹,并取出当中所有文件的路径
				 */
				//StaticUtil.unzip(fileUri);
				//StaticUtil.deleteFile(fileUri);
				String dirPath = fileUri;
				String foldName = dirPath.substring(dirPath.lastIndexOf("/") + 1, dirPath.length());
			/*	fileMap = StaticUtil.getAllFiles(dirPath, foldName, job.getJobHash());
				for (int i = 0; i < fileMap.size(); i++) {
					fileUri = fileMap.get(i);

					// 远端路径重拼装
					ftpFileUri = ftpFileUri.substring(0, ftpFileUri.lastIndexOf("/"))
							+ fileUri.substring(fileUri.lastIndexOf("/"));
					updateState(ftpFileUri, generateScriptFile(ftpFileUri, fileUri), postfix, result);
					if (fileUri.contains(job.getJobHash())) {
						StaticUtil.deleteFile(fileUri);
					}
				}*/
				//不解压
				updateState(ftpFileUri, generateScriptFile(ftpFileUri, fileUri), postfix, result);
				
				
				if (fileUri.contains(job.getJobHash())) {
					StaticUtil.deleteFile(fileUri.substring(0, fileUri.lastIndexOf("/") + 1));
					StaticUtil.deleteFile(dirPath);
				}
			} else {
				/**
				 * 如果是其他情况，则ftpFileUri是早已封装好的，不需再处理
				 */
				updateState(ftpFileUri, generateScriptFile(ftpFileUri, fileUri), postfix, result);
				if (fileUri.contains(job.getJobHash())) {
					StaticUtil.deleteFile(fileUri);
				}
			}
			return result;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	private HttpResult updateState(String ftpFileUri, String batUri, String postfix, List<String> result) {
		HttpResult httpResult = new HttpResult();
		if (createFolders(ftpFileUri)) {
			httpResult.setMessage("上传文件时，创建目录成功");
			if (runBat(batUri)) {
				StaticUtil.deleteFile(batUri);
				result.add(ftpFileUri);
			} else {
				httpResult.setMessage("上传文件时，运行" + postfix + "文件失败");
				httpResult.setResult(false);
			}
		} else {
			httpResult.setMessage("上传文件时，创建目录失败");
			httpResult.setResult(false);
		}
		return httpResult;
	}

	/**
	 * @param userName
	 *            : here not use
	 * @param passWord
	 *            : here not use
	 * @return token
	 */
	public static HttpResult getToken(String userName, String passWord) {
		if (!HttpConfig.fake) {
			String token = TokenValue.TOKEN.getTokenValue(HttpConfig.userName, HttpConfig.passWord);
			if (token != null) {
				return new HttpResult(true, token);
			} else {
				return new HttpResult(false, "服务器错误！");
			}
		} else {
			return new HttpResult(true, "fakeToken");
		}
	}

	/**
	 * 给ftp中创建文件夹
	 * 
	 * @param ftpFileUri
	 * @return
	 */
	private boolean createFolders(String ftpFileUri) {
		if (!HttpConfig.fake) {
			String targetUri = ftpFileUri.substring(0, ftpFileUri.lastIndexOf("/") + 1);
			String params = "dirpath=" + targetUri + "&isforce=true&token="
					+ getToken(HttpConfig.userName, HttpConfig.passWord).getMessage();
			JSONObject result = JSONObject.fromObject(HttpRequest.sendGet(HttpConfig.createFtpFolder, params));
			if (result.getString("result").equals("success")) {
				Log4jInit.logger.info("*******create ftp file sucess*******");
				return true;
			} else {
				return false;
			}
		} else {
			return true;
		}
	}

	/**
	 * 运行脚本文件，将本地文件通过ftp上传至ftp
	 * 
	 * @param batUri
	 */
	private boolean runBat(String batUri) {
		boolean result = false;
		if (!HttpConfig.fake &&(!batUri.equals(""))) {
			Process p;
			try {
				chmod(batUri);
				// 执行命令
				p = Runtime.getRuntime().exec(batUri);

				/* 为"错误输出流"单独开一个线程读取之,否则会造成标准输出流的阻塞 */
				Thread t = new Thread(new StreamGobbler(p.getErrorStream(), "ErrorStream"));
				t.start();

				// 取得命令结果的输出流
				InputStream fis = p.getInputStream();
				// 用一个读输出流类去读
				InputStreamReader isr = new InputStreamReader(fis, "gbk");
				// 用缓冲器读行
				BufferedReader br = new BufferedReader(isr);
				String line = null;
				// 直到读完为止
				while ((line = br.readLine()) != null) {
					if (line.equals("upload file success")) {
						result = true;
					}
				}
				File f = new File(batUri);
				f.delete();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return result;
		} else {
			return true;
		}
	}

	/**
	 * 生成上传ftp文件的脚本文件
	 * 
	 * @param ftpFileUri
	 *            ftpFile文件路径
	 * @param fileUri
	 *            本地文件路径
	 * @return
	 * @throws IOException
	 */
	private String generateScriptFile(String ftpFileUri, String fileUri) throws IOException {

		if(fileUri.equals("")||fileUri.equals(null)){
			return "";
		}
		
		String command = uploadToolUri + " -m " + HttpConfig.uploadIP + " -l " + fileUri + " -r " + ftpFileUri
				+ " -u -n jhadmin";
		Log4jInit.logger.info("ftp command::::" + command);
		String scriptFileUri = HttpConfig.scriptFileUri;
		File scriptFile = new File(scriptFileUri);
		if (!scriptFile.exists()) {
			scriptFile.mkdirs();
			chmod(scriptFileUri);
		}
		String scriptUri = scriptFileUri + UUID.randomUUID().toString().substring(0, 20) + postfix;
		File algorithmBatFile = new File(scriptUri);
		FileWriter fw = new FileWriter(algorithmBatFile);
		chmod(scriptUri);
		fw.write(command);
		fw.close();
		return scriptUri;
	}

}

